/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.dabarobjects.path;

import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Deji Aladejebi
 */
public final class Path implements Serializable {

    private Path() {
        seperator = System.getProperty("file.separator");
        pathAggregate = "/";
    }
    private String seperator;
    private String pathAggregate;

    @SuppressWarnings("static-access")
    public final static Path drive(String letter) {
        Path drive = new Path();
        String osRootToken = System.getProperty("os.name").indexOf("Windows") != -1 ? ":" : "";
        drive.pathAggregate = drive.getPathAggregate().concat(letter).concat(osRootToken).concat(drive.getSeperator());
        return drive;
    }

    public final static Path root() {
        Path drive = new Path();
        return drive;
    }

    public final Path folder(String foldername) {
        pathAggregate = getPathAggregate().concat(foldername).concat(getSeperator());
        return this;
    }

    public final Path disk(String letter) {
        Path drive = new Path(); 

        String osRootToken = System.getProperty("os.name").indexOf("Windows") != -1 ? ":" : "";
        drive.pathAggregate = drive.getPathAggregate().concat(letter).concat(osRootToken).concat(drive.getSeperator());
        return drive;
    }

    public final static Path home() {
        Path drive = new Path();
        String foldername = System.getProperty("user.home");
        drive.pathAggregate = foldername.concat(drive.getSeperator());
        return drive;
    }

    public final static Path here() {
        Path drive = new Path();
        String foldername = System.getProperty("user.dir");
        drive.pathAggregate = foldername.concat(drive.getSeperator());
        return drive;
    }

    public final static Path here(File file) {
        Path drive = new Path();
        String foldername = file.getAbsolutePath();
        drive.pathAggregate = foldername.concat(drive.getSeperator());
        return drive;
    }

    public final static Path java() {
        Path drive = new Path();
        String foldername = System.getProperty("java.home");
        drive.pathAggregate = foldername.concat(drive.getSeperator());
        return drive;
    }

    /**
     *
     * @param path
     * @return the first path found that is absolutely equivalent to the specified subpath within the current directory
     */
    public final Path find(String path) {
        long start = System.nanoTime();
        File current = file();
        //remove slashes
        if (path.lastIndexOf(getPathAggregate()) != -1) {
            path = path.substring(0, path.length() - 1);
        }

        //check the current directory
        firstFind(current, path, false);
        //then scan the remaing sub directories
        nestFind(path, current, false);

        long end = System.nanoTime();
        System.out.println("Time: " + (end - start)/(1000 * 1000 * 1000));
        return this;
    }

    public final List<Path> finds(String path) {
        File current = file();
        finds = new ArrayList<Path>();
        //remove slashes
        if (path.lastIndexOf(getPathAggregate()) != -1) {
            path = path.substring(0, path.length() - 1);
        }

        firstFind(current, path, true);
        nestFind(path, current, true);
        return finds;
    }
    private List<Path> finds;

    private void firstFind(File first, String path, boolean all) {
        if (first.isDirectory()) {
            File firstFound = new File(first.getAbsolutePath().concat(getSeperator()).concat(path));
            if (firstFound.exists()) {
                if (all) {
                    finds.add(Path.here(firstFound));
                } else {
                    pathAggregate = first.getAbsolutePath().concat(getSeperator()).concat(path);
                }
            }
        } else {
            if (first.getName().equalsIgnoreCase(path)) {
                if (all) {
                    finds.add(Path.here(first));
                } else { 
                    pathAggregate = first.getAbsolutePath();
                }
            }
        }
    }

    private void nestFind(String path, File folder, boolean all) {

        File fp[] = folder.listFiles();
        if (fp != null) {
            for (int io = 0; io < fp.length; io++) {
                if (fp[io].isDirectory()) {
                    File firstFound = new File(fp[io].getAbsolutePath().concat(getSeperator()).concat(path));
                    if (firstFound.exists()) {
                        if (all) {
                            finds.add(Path.here(firstFound));
                        } else {
                            pathAggregate = fp[io].getAbsolutePath().concat(getSeperator()).concat(path);
                            break;
                        }
                    }
                    nestFind(path, fp[io], all);
                } else {
                    if (fp[io].getName().equalsIgnoreCase(path)) {
                        if (all) {
                            finds.add(Path.here(fp[io]));
                        } else {
                            pathAggregate = fp[io].getAbsolutePath();
                            break;
                        }
                    }
                }
            }
        }
    }

    private final String getSeperator() {
        return seperator;
    }

    private final String getPathAggregate() {
        return pathAggregate;
    }

    public final File file(String filename) {
        pathAggregate = getPathAggregate().concat(filename);
        return file();
    }

    public final Path link(String filename) {
        pathAggregate = getPathAggregate().concat(filename);
        return this;
    }

    public final File file() {
        return new File(pathAggregate);
    }

    public final String out() {
        return getPathAggregate();
    }

    @Override
    public String toString() {
        return getPathAggregate();
    }
}
